﻿using Coolzon.Common;
using Coolzon.Metadata.Runtime;
using Coolzon.UI.Common.Widgets.DataTask;
using Coolzon.UI.Common.Widgets.Properties;
using Coolzon.UI.Core;
using Coolzon.UI.Core.Parts;
using Coolzon.UI.Core.Properties;
using Coolzon.Web.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using RT = Coolzon.Metadata.Runtime;

namespace Coolzon.UI.Common.Widgets
{
    /// <summary>
    /// 数据组件
    /// </summary>
    public partial class DataWidget : Widget
    {
        /// <summary>
        /// 是否在加载数据中
        /// </summary>
        private bool _isLoadingData = false;
        /// <summary>
        /// 数据开始加载的时间
        /// </summary>
        private long _beginDataLoadTicks = 0;

        #region script events definition
        /// <summary>
        /// 组件绑定数据时触发的事件
        /// 这个通过xml文件来设置
        /// </summary>
        public string EventStringOnDataBinding;
        #endregion

        #region Private variables

        public string DataSourceName { get; set; }
        public string DataSetName { get; set; }
        public QueryParameter[] DataParameters { get; set; }

        private DataResult _dataResult;
        public DataResult DataResult
        {
            get
            {
                return _dataResult;
            }
            set
            {
                _dataResult = value;
            }
        }

        DispatcherTimer _timer;
        #endregion

        private PartContext _context;

        /// <summary>
        /// 通过_activeTicks和_timerTicks来判断是激活绑定数据还是刷新绑定数据
        /// 激活方法调用的时间
        /// </summary>
        private long _activeTicks;
        /// <summary>
        /// 定时刷新方法调用的时间
        /// </summary>
        private long _refreshTicks;
        /// <summary>
        /// 是否启用数据缓存
        /// </summary>
        private bool _isEnableDataCache;

        /// <summary>
        /// 是否是第一次绑定数据
        /// </summary>
        public bool IsFirstDataBind
        {
            get;
            private set;
        }

        #region XEvents
        ///// <summary>
        ///// DataBind脚本事件
        ///// </summary>
        //public static XEvent XEventOnDataBind = XEventManager.Register(typeof(DataPart),
        //    "OnDataBind",
        //    new XEventArgument("sender", typeof(Script.PartScriptObject)),
        //    new XEventArgument("data", typeof(Script.DataResultScriptObject)));
        #endregion

        public DataWidget()
        {
            //XColorPlate = new ColorPlate();
            //AddColors();

            XDataAnimationDuration = 1;
            IsFirstDataBind = true;
            XAutoRefreshInterval = 5;
        }

        #region implement Widget
        protected override void OnInit(PartContext context)
        {
            this.EventStringOnDataBinding = this.Metadata.GetScriptEventValue(RT.ScriptEvent.OnDataBinding);

            //BindData(context);
            base.OnInit(context);
        }

        protected override void OnActive(PartContext context)
        {
            _activeTicks = DateTime.Now.Ticks;
            _context = context;

            if (XIsAutoRefresh)
            {
                //Common.Logger.DebugToTag("UI", "part:{0} start timer interval:{1}", this.Name, XAutoRefreshInterval);
                if (_timer == null)
                {
                    _timer = new DispatcherTimer();
                    _timer.Tick += OnAutoRefreshTimerTick;
                    _timer.Interval = TimeSpan.FromSeconds(XAutoRefreshInterval);
                    _timer.Start();
                    Logger.DebugToTag(Library.LogDispatcherTimerTAG, string.Format("组件：{0}的自动刷新定时器构造并启动", this.Name));
                }
            }

            _isEnableDataCache = XIsAutoRefresh == false && PartContext.DataCacheMode == DataCacheMode.All;
            LoadData(context, _isEnableDataCache);

            base.OnActive(context);
        }

        protected override void OnDeactive()
        {
            ////设计器不清除数据
            //if (this._dataResult != null && !string.Equals(System.Configuration.ConfigurationManager.AppSettings["SysName"], "Designer"))
            //{
            //    // 清空数据
            //    this._dataResult = null;
            //}

            if (_timer != null)
            {
                Logger.DebugToTag(Library.LogDispatcherTimerTAG, string.Format("组件：{0}的自动刷新定时器停止并删除", this.Name));
                _timer.Tick -= OnAutoRefreshTimerTick;
                _timer.Stop();
                _timer = null;
            }
            base.OnDeactive();
        }

        protected override void OnDestroy()
        {
            if (_timer != null)
            {
                Logger.DebugToTag(Library.LogDispatcherTimerTAG, string.Format("组件：{0}的自动刷新定时器停止并删除", this.Name));
                _timer.Tick -= OnAutoRefreshTimerTick;
                _timer.Stop();
                _timer = null;
            }
            base.OnDestroy();
        }
        #endregion

        /// <summary>
        /// 刷新数据
        /// </summary>
        protected override void OnRefresh()
        {
            //if (_dataResult != null)
            //{
            //    if (IsActived)
            //    {
            //        DataBinding(_dataResult);
            //        IsFirstDataBind = false;
            //    }
            //}
            //else
            //{
            //    LoadData(this.PartContext, false);
            //}
        }

        private void OnAutoRefreshTimerTick(object sender, EventArgs e)
        {
            if (XDataSource == null)
                return;

            this._refreshTicks = DateTime.Now.Ticks;
            // 向服务器请求数据
            if (_isLoadingData)
            {
                long timeoutTime = DateTime.Now.Ticks - _beginDataLoadTicks;
                if (timeoutTime > TimeSpan.FromSeconds(30).Ticks)
                {
                    //Logger.InfoToTag("UI", "控件{0}正在加载数据，上次数据加载超时", this.Name);
                    _isLoadingData = false;
                }
                else
                {
                    //Logger.InfoToTag("UI", "控件{0}正在加载数据，本次不执行加载数据操作", this.Name);
                    return;
                }
            }

            _beginDataLoadTicks = DateTime.Now.Ticks;

            RunAsync(StartDataLoadTask);
        }

        /// <summary>
        /// 绑定数据
        /// </summary>
        /// <param name="context"></param>
        /// <param name="isCacheEnable">是否支持缓存</param>
        public void LoadData(PartContext context, bool isCacheEnable)
        {
            if (_dataResult != null)
            {
                if (IsActived)
                {
                    DataBinding(_dataResult);
                    IsFirstDataBind = false;
                }
            }
            else
            {
                RunAsync(StartDataLoadTask);
            }
        }

        public static async void RunAsync(Action function)
        {
            Func<System.Threading.Tasks.Task> taskFunc = () =>
            {
                return System.Threading.Tasks.Task.Run(() =>
                {
                    function();
                });
            };
            await taskFunc();
        } 

        private void StartDataLoadTask()
        {
            if (XDataSource != null)
            {
                _isLoadingData = true;
                _beginDataLoadTicks = DateTime.Now.Ticks;

                List<QueryParameter> parameters = new List<QueryParameter>();

                // 如果是静态数据源，没有dataset和parameter的设置
                if (XDataSource.DataSet != null && XDataSource.DataSet.Parameters != null)
                {
                    for (int index = 0; index < XDataSource.DataSet.Parameters.Count; index++)
                    {
                        DataParameter dataParameter = XDataSource.DataSet.Parameters[index];
                        QueryParameter parameter = new QueryParameter();
                        parameter.Name = dataParameter.Name;
                        parameter.Type = dataParameter.Type;
                        parameter.ValueString = ParseValueString(dataParameter.ValueString);
                        parameters.Add(parameter);
                    }
                }

                DataLoadTaskManager.Run(new DataLoadTask(this,
                    "",
                    XDataSource,
                    XDataSource.DataSet,
                    parameters,
                    _isEnableDataCache));
            }
        }

        /// <summary>
        /// 数据加载完毕之后，此方法将被调用
        /// </summary>
        /// <param name="result"></param>
        public void OnLoadDataCompleted(DataResult result)
        {
            _isLoadingData = false;
            if (result != null)
            {
                this._dataResult = ScreeningDataSeries(result);
            }
            else
            {
                this._dataResult = null;
            }

            if (!this.IsActived || this.Visibility != System.Windows.Visibility.Visible)
            {
                return;
            }

            if (this.Dispatcher.HasShutdownFinished == false)
            {
                // 程序没有关闭才执行下面的代码
                this.Dispatcher.BeginInvoke(new Action(OnDataBindingToUI));
            }
        }

        private void OnDataBindingToUI()
        {
            try
            {
                if (_dataResult != null)
                {
                    if (!string.IsNullOrEmpty(EventStringOnDataBinding))
                    {
                        this.PartContext.ScriptEngine.Run(EventStringOnDataBinding, this.GetScriptObject(), _dataResult);
                    }
                    DataBinding(_dataResult);
                }
            }
            catch (Exception ex)
            {
                Logger.ErrorToTag("UI", string.Format("OnDataClientGetDataCompleted 出错!ex:{0}", ex));
            }
        }

        //protected override void OnInitScriptEngine(ScriptEngine engine)
        //{
        //    base.OnInitScriptEngine(engine);
        //}

        private void DataBinding(DataResult dataResult)
        {
            if(this._activeTicks > this._refreshTicks)
            {
                OnDataBinding(new DataBindingArgs(DataBindingReason.Active, dataResult));
            }
            else
            {
                OnDataBinding(new DataBindingArgs(DataBindingReason.Refresh, dataResult));
            }

            IsFirstDataBind = false;
            ValidateDisplayCondition();

            //// 调用脚本
            //if (HasScriptEvent(DataPart.XEventOnDataBind.Name))
            //{
            //    this.InvokeScriptEvent(PartContext.ScriptEngine, DataPart.XEventOnDataBind.Name, this.GetScriptObj(), new Script.DataResultScriptObject(dataResult));
            //}
        }

        protected virtual void OnDataBinding(DataBindingArgs args)
        {

        }

        ///// <summary>
        ///// 触发事件
        ///// </summary>
        ///// <param name="eventType"></param>
        ///// <param name="dataItem">触发事件的项目所在的数据项</param>
        //protected void RaiseEvent(DataEventType eventType, ServiceProxy.DataServiceRef.DataItem dataItem)
        //{
        //    return;
        //    /*
        //    if (this.EventList != null)
        //    {
        //        // 扫描组件的所有事件配置
        //        ScriptEngine script = ScriptEngine.Instance;
        //        script.AddCode("var args={data:{id:'" + dataItem.Id + "', name:'" + dataItem.Name + "', value:'" + dataItem.Value + "'}};");
        //        for (int index = 0; index < this.EventList.Count; index++)
        //        {
        //            Metadata.Event @event = this.EventList[index];
        //            // 检查事件类型
        //            if (@event.Source.ToUpper() == GetDataEventTypeString(eventType))
        //            {
        //                // 检查事件条件
        //                if (string.IsNullOrEmpty(@event.Condition)
        //                    || (bool)script.RunExpression(@event.Condition))
        //                {
        //                    // 往事件总线中发送数据交互事件
        //                    ActionUrl url = new ActionUrl(@event.Action);
        //                    EventContext context = new EventContext();
        //                    context.ActionType = url.ActionType;
        //                    context.TargetFrameName = url.TargetFrame;
        //                    context.TargetSceneName = url.TargetScene;

        //                    this.InjectionParameters(context, dataItem, url);

        //                    // 向事件总线发送组件事件响应事件
        //                    Common.EventBus.Instance.Publish(context);
        //                }
        //            }
        //        }
        //    }
        //     * */
        //}

        /// <summary>
        /// 注入参数的值,最终将值注入到context中，具体有什么值根据url中的parameterstring来定义
        /// </summary>
        /// <param name="context"></param>
        /// <param name="url"></param>
        protected void InjectionParameters(EventContext context, DataItem dataItem, ActionUrl url)
        {
            // 更细参数的值
            foreach (string key in url.ParameterString.Keys)
            {
                if (context.Arguments.ContainsKey(key))
                {
                    continue;
                }
                string pValue = url.ParameterString[key];
                if (pValue == "args.data.id")
                {
                    context.Arguments.Add(key, dataItem.Id);
                }
                else if (pValue == "args.data.name")
                {
                    context.Arguments.Add(key, dataItem.Name);
                }
                else if (pValue == "args.data.value")
                {
                    context.Arguments.Add(key, dataItem.Value);
                }
            }

            base.InjectionParameters(context, url);
        }

        //private string GetDataEventTypeString(DataEventType eventType)
        //{
        //    if (eventType == DataEventType.Click)
        //    {
        //        return "ITEMCLICK";
        //    }
        //    return "UNKNOWN";
        //}

        /// <summary>
        /// 过滤数据串
        /// </summary>
        /// <param name="originalData"></param>
        /// <returns></returns>
        private DataResult ScreeningDataSeries(DataResult originalData)
        {
            if (originalData == null)
            {
                return null;
            }
            else if (XDataSeriesFilter == null || XDataSeriesFilter.Count == 0)
            {
                if (XDataItemFilter != null && XDataItemFilter.Count > 0)
                {
                    List<DataSeries> newSeriesList = new List<DataSeries>();
                    for (int iSeries = 0; iSeries < originalData.DataSeries.Count; iSeries++)
                    {
                        DataSeries originalSeries = originalData.DataSeries[iSeries];

                        DataSeries newSeries = new DataSeries();
                        newSeries.Id = originalSeries.Id;
                        newSeries.Name = originalSeries.Name;
                        newSeries.DataItems = new List<DataItem>();

                        List<DataItem> itemList = new List<DataItem>();
                        foreach (var itemId in XDataItemFilter)
                        {
                            for (int iItem = 0; iItem < originalSeries.DataItems.Count; iItem++)
                            {
                                DataItem item = originalSeries.DataItems[iItem];
                                if (item.Id == itemId)
                                {
                                    newSeries.DataItems.Add(item);
                                }
                            }
                        }

                        newSeriesList.Add(newSeries);
                    }

                    DataResult result = new DataResult();
                    result.Name = originalData.Name;
                    result.DataSeries = newSeriesList;
                    return result;
                }
                else
                {
                    return originalData;
                }
            }
            else
            {

                if (XDataItemFilter != null && XDataItemFilter.Count > 0)
                {
                    List<DataSeries> newSeriesList = new List<DataSeries>();
                    foreach (var seriesId in XDataSeriesFilter)
                    {
                        for (int iSeries = 0; iSeries < originalData.DataSeries.Count; iSeries++)
                        {
                            DataSeries originalSeries = originalData.DataSeries[iSeries];

                            if (originalSeries.Id == seriesId)
                            {
                                DataSeries newSeries = new DataSeries();
                                newSeries.Id = originalSeries.Id;
                                newSeries.Name = originalSeries.Name;
                                List<DataItem> newItemList = new List<DataItem>();
                                foreach (var itemId in XDataItemFilter)
                                {
                                    for (int iItem = 0; iItem < originalSeries.DataItems.Count; iItem++)
                                    {
                                        DataItem item = originalSeries.DataItems[iItem];
                                        if (item.Id == itemId)
                                        {
                                            newItemList.Add(item);
                                        }
                                    }
                                }
                                newSeries.DataItems = newItemList;

                                newSeriesList.Add(newSeries);
                            }
                        }
                    }

                    DataResult result = new DataResult();
                    result.Name = originalData.Name;
                    result.DataSeries = newSeriesList;
                    return result;
                }
                else
                {
                    List<DataSeries> seriesList = new List<DataSeries>();
                    foreach (var seriesId in XDataSeriesFilter)
                    {
                        for (int iSeries = 0; iSeries < originalData.DataSeries.Count; iSeries++)
                        {
                            if (originalData.DataSeries[iSeries].Id == seriesId)
                            {
                                List<DataItem> itemList = new List<DataItem>();

                                seriesList.Add(originalData.DataSeries[iSeries]);
                            }
                        }
                    }

                    DataResult result = new DataResult();
                    result.Name = originalData.Name;
                    result.DataSeries = seriesList;
                    return result;
                }
            }
        }

        #region implement IDataPart

        //public void LoadData()
        //{
        //    if (XDataSource != null)
        //    {
        //        List<ServiceProxy.DataServiceRef.DataParameter> parameters = new List<ServiceProxy.DataServiceRef.DataParameter>();
        //        for (int index = 0; index < XDataSource.DataSet.Parameters.Count; index++)
        //        {
        //            UI.DataParameter dataParameter = XDataSource.DataSet.Parameters[index];
        //            ServiceProxy.DataServiceRef.DataParameter parameter = new ServiceProxy.DataServiceRef.DataParameter();
        //            parameter.Name = dataParameter.Name;
        //            parameter.Type = dataParameter.Type;
        //            parameter.ValueString = ParseValueString(dataParameter.ValueString);
        //            parameters.Add(parameter);
        //        }
        //        // 预加载模式，同步读取
        //        DataLoadTaskManager.Run(new DataLoadTask(this,
        //            "",
        //            XDataSource,
        //            XDataSource.DataSet,
        //            parameters));
        //    }
        //}

        #endregion


        ///// <summary>
        ///// 根据颜色板应用颜色值
        ///// </summary>
        ///// <param name="chart"></param>
        ///// <param name="colorPlate"></param>
        //protected virtual void ApplyChartColorPlate(Chart chart, ColorPlate colorPlate)
        //{
        //    if (this.XColorPlate == null)
        //    {
        //        return;
        //    }
        //    if (chart.Series != null && chart.Series.Count > 0)
        //    {
        //        for (int i = 0; i < chart.Series.Count; i++)
        //        {
        //            chart.Series[i].Color = this.XColorPlate.GetColor(i);
        //        }
        //    }
        //}
    }
}
